package com.tanhua.gateway.filters;

import com.alibaba.fastjson.JSON;
import com.tanhua.commons.utils.JwtUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 统一鉴权过滤器
 *   1、交给容器管理
 *   2、实现GloadbleFilter和Orderd接口
 *   3、实现内部的两个方法，指定过滤器的优先级
 *   4、在filter方法中，指定过滤器的业务逻辑代码
 */
@Component
public class AuthFilter implements GlobalFilter, Ordered {

    //@Value可以将字符串转化为list集合（字符串需要以“，”分割）
    @Value("${gateway.excludedUrls}")
    private List<String> excludeUrls; //定义所有不需要验证token的url

    /**
     * 统一鉴权过滤器（对所有的web工程，在请求转发之前进行token的验证）
     *  exchange：请求上下文
     *  chain：过滤器链
     */
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        //1、获取当前请求的URL
        String path = request.getURI().getPath();  //请求地址  /login
        //2、判断此URL是否需要经过token校验
        if(excludeUrls.contains(path)) {
            //3、如果此URL不需要校验，直接放行（路由转发到web工程）
            return chain.filter(exchange);
        }
        //4、需要token校验，获取请求头中的token
        String token = request.getHeaders().getFirst("Authorization");
        if(!StringUtils.isEmpty(token)) {
           token = token.replaceAll("Bearer ",""); //解决vue页面，传递token包含“Bearer ”的问题
        }
        //5、调用JtwUtils工具类，检测token是否有效
        boolean verifyToken = JwtUtils.verifyToken(token);
        //6、如果token有效，直接放行（路由转发到web工程）
        if(verifyToken) {
            return chain.filter(exchange);
        }
        //7、如果token失效，返回状态码401，并响应
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        //return response.setComplete();
        //8、如果token失效，拦截请求，响应数据
        Map<String,Object> map = new HashMap<>();
        map.put("errCode", 401);
        map.put("errMessage", "用户未登录");
        //指定相应的数据头
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        //需要将返回的对象数据转化为byte数组
        byte[] data = JSON.toJSONBytes(map);
        //构造DataBuffer对象
        DataBuffer buffer = response.bufferFactory().wrap(data); //数据DatBuffer
        return response.writeWith(Mono.just(buffer));
    }

    //指定过滤器的优先级,值越小，优先级越大
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}
